package com.totoro.tyrank.handle;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.totoro.tyrank.TyRank;
import net.minecraft.server.v1_12_R1.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scheduler.BukkitRunnable;

import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

public class SkullCacheHandler {
    // 缓存配置
    private static final int CACHE_SIZE = 5000;
    private static final int MAX_BATCH_SIZE = 100;
    private static final long CACHE_EXPIRE_MINUTES = 30;

    // UUID正则检测
    private static final Pattern UUID_PATTERN = Pattern.compile(
            "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
            Pattern.CASE_INSENSITIVE
    );

    // 多级缓存系统
    private final Cache<String, ItemStack> skullCache = CacheBuilder.newBuilder()
            .maximumSize(CACHE_SIZE)
            .expireAfterAccess(CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES)
            .build();

    private final Cache<String, UUID> uuidCache = CacheBuilder.newBuilder()
            .maximumSize(CACHE_SIZE)
            .build();

    private final Cache<UUID, String> textureCache = CacheBuilder.newBuilder()
            .maximumSize(CACHE_SIZE)
            .build();

    // 反射字段缓存
    private static Field profileField;
    static {
        try {
            ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
            SkullMeta meta = (SkullMeta) skull.getItemMeta();
            profileField = meta.getClass().getDeclaredField("profile");
            profileField.setAccessible(true);
        } catch (Exception e) {
            Bukkit.getLogger().severe("反射初始化失败: " + e.getMessage());
        }
    }

    // 线程池优化
    private final ExecutorService ioExecutor;
    private final TyRank plugin;

    // 默认Steve纹理
    private static final String STEVE_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGYxN2I0ZDk4ODFiZjUxZTRhYjUyZTg2ZjRkYzJmYmQ1NDk1YzQ1ZGE1N2Q3YjI4NSJ9fX0=";

    public SkullCacheHandler(TyRank plugin) {
        this.plugin = plugin;

        // 优化线程池配置
        int cores = Runtime.getRuntime().availableProcessors();
        int poolSize = Math.max(2, Math.min(cores, 4)); // 限制线程数量

        ioExecutor = new ThreadPoolExecutor(
                poolSize, poolSize,
                30L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000),
                r -> {
                    Thread t = new Thread(r, "SkullCache-IO");
                    t.setPriority(Thread.MIN_PRIORITY);
                    return t;
                },
                new ThreadPoolExecutor.CallerRunsPolicy() // 防止任务堆积
        );
    }

    /**
     * 批量缓存并预加载纹理 (异步)
     */
    public CompletableFuture<Void> batchCacheSkulls(List<String> identifiers) {
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        AtomicInteger count = new AtomicInteger();

        // 分批处理防止内存溢出
        for (int i = 0; i < identifiers.size(); i += MAX_BATCH_SIZE) {
            int end = Math.min(i + MAX_BATCH_SIZE, identifiers.size());
            List<String> batch = identifiers.subList(i, end);

            futures.add(CompletableFuture.runAsync(() -> {
                batch.forEach(identifier -> {
                    if (identifier == null || identifier.trim().isEmpty()) return;

                    try {
                        // 确保缓存存在
                        getCachedSkull(identifier);

                        if (count.incrementAndGet() % 100 == 0) {
                            plugin.getLogger().info("已缓存: " + count.get() + "/" + identifiers.size());
                        }
                    } catch (Exception e) {
                        plugin.getLogger().warning("缓存失败: " + e.getMessage());
                    }
                });
            }, ioExecutor));
        }

        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
    }

    /**
     * 获取缓存头颅（高性能版本）
     */
    public ItemStack getCachedSkull(String identifier) {
        // 1. 检查一级缓存
        ItemStack cached = skullCache.getIfPresent(identifier);
        if (cached != null) return cached.clone();

        // 2. 解析标识符类型
        UUID uuid = resolveIdentifier(identifier);
        if (uuid == null) return getFallbackSkull();

        // 3. 获取纹理（优先缓存）
        String texture = textureCache.getIfPresent(uuid);
        if (texture == null) {
            texture = resolveTexture(uuid);
            if (texture == null) texture = STEVE_TEXTURE;
            textureCache.put(uuid, texture);
        }

        // 4. 创建头颅（避免NMS操作）
        ItemStack skull = createSkullFast(uuid, texture);

        // 5. 更新缓存
        skullCache.put(identifier, skull.clone());
        return skull;
    }

    /**
     * 高性能标识符解析
     */
    private UUID resolveIdentifier(String identifier) {
        String key = identifier.toLowerCase();

        // 1. 检查UUID缓存
        UUID cached = uuidCache.getIfPresent(key);
        if (cached != null) return cached;

        // 2. 检查是否为UUID格式
        if (isUUID(identifier)) {
            UUID uuid = UUID.fromString(identifier);
            uuidCache.put(key, uuid);
            return uuid;
        }

        // 3. 精简UUID格式处理
        if (identifier.length() == 32) {
            try {
                UUID uuid = UUID.fromString(identifier.substring(0, 8) + "-" +
                        identifier.substring(8, 12) + "-" +
                        identifier.substring(12, 16) + "-" +
                        identifier.substring(16, 20) + "-" +
                        identifier.substring(20));
                uuidCache.put(key, uuid);
                return uuid;
            } catch (Exception ignored) {}
        }

        // 4. 在线玩家检查
        Player player = Bukkit.getPlayerExact(identifier);
        if (player != null) {
            UUID uuid = player.getUniqueId();
            uuidCache.put(key, uuid);
            return uuid;
        }

        // 5. 离线玩家检查
        OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(identifier);
        if (offlinePlayer.hasPlayedBefore()) {
            UUID uuid = offlinePlayer.getUniqueId();
            uuidCache.put(key, uuid);
            return uuid;
        }

        // 6. Mojang API查询（异步缓存）
        ioExecutor.execute(() -> {
            UUID uuid = fetchMojangUUID(identifier);
            if (uuid != null) {
                uuidCache.put(key, uuid);
                // 预加载纹理
                String texture = resolveTexture(uuid);
                if (texture != null) {
                    textureCache.put(uuid, texture);
                }
            }
        });

        return null;
    }

    /**
     * 高性能纹理解析
     */
    private String resolveTexture(UUID uuid) {
        // 1. 在线玩家纹理获取
        Player player = Bukkit.getPlayer(uuid);
        if (player != null) {
            return getOnlineTexture((CraftPlayer) player);
        }

        // 2. 缓存检查
        String cached = textureCache.getIfPresent(uuid);
        if (cached != null) return cached;

        // 3. Mojang API查询
        return fetchMojangTexture(uuid);
    }

    /**
     * 快速创建头颅（避免NMS操作）
     */
    private ItemStack createSkullFast(UUID uuid, String texture) {
        try {
            ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
            SkullMeta meta = (SkullMeta) skull.getItemMeta();

            // 使用反射直接设置GameProfile
            GameProfile profile = new GameProfile(uuid, "SkullOwner");
            profile.getProperties().put("textures", new Property("textures", texture));

            profileField.set(meta, profile);
            skull.setItemMeta(meta);
            return skull;
        } catch (Exception e) {
            return getFallbackSkull();
        }
    }

    /**
     * 获取在线玩家纹理
     */
    private String getOnlineTexture(CraftPlayer player) {
        try {
            EntityPlayer entityPlayer = player.getHandle();
            GameProfile profile = entityPlayer.getProfile();
            Property property = profile.getProperties().get("textures").iterator().next();
            return property.getValue();
        } catch (Exception e) {
            return STEVE_TEXTURE;
        }
    }

    /**
     * Mojang API交互 - UUID
     */
    private UUID fetchMojangUUID(String name) {
        try {
            URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(2000);

            if (conn.getResponseCode() == 200) {
                JsonObject json = new JsonParser().parse(new InputStreamReader(conn.getInputStream())).getAsJsonObject();
                String uuidStr = json.get("id").getAsString();

                // 格式化UUID
                return UUID.fromString(
                        uuidStr.replaceFirst(
                                "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})",
                                "$1-$2-$3-$4-$5"
                        )
                );
            }
        } catch (Exception ignored) {}
        return null;
    }

    /**
     * Mojang API交互 - 纹理
     */
    private String fetchMojangTexture(UUID uuid) {
        try {
            URL url = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" +
                    uuid.toString().replace("-", "") + "?unsigned=false");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(2000);

            if (conn.getResponseCode() == 200) {
                JsonObject json = new JsonParser().parse(new InputStreamReader(conn.getInputStream())).getAsJsonObject();
                return json.getAsJsonArray("properties").get(0).getAsJsonObject().get("value").getAsString();
            }
        } catch (Exception ignored) {}
        return STEVE_TEXTURE;
    }

    /**
     * 备用头颅
     */
    private ItemStack getFallbackSkull() {
        ItemStack head = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
        SkullMeta meta = (SkullMeta) head.getItemMeta();
        meta.setOwner("Steve");
        head.setItemMeta(meta);
        return head;
    }

    private boolean isUUID(String input) {
        return UUID_PATTERN.matcher(input).matches();
    }

    /**
     * 关闭时清理资源
     */
    public void shutdown() {
        ioExecutor.shutdown();
        try {
            if (!ioExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                ioExecutor.shutdownNow();
            }
        } catch (InterruptedException ignored) {
            Thread.currentThread().interrupt();
        }
    }
}